#ifndef OA_UTIL_STRINGUTIL_H
#define OA_UTIL_STRINGUTIL_H

#include "libs.h"

namespace util {
	//predicate structure
	struct IsSpace: public std::unary_function<char, bool> {
		#if OA_PLATFORM == PLATFORM_WIN32
			IsSpace(const std::locale& loc = std::locale("english")): mLocale(loc) {}

		#elif OA_PLATFORM == PLATFORM_APPLE
			IsSpace(const std::locale& loc = std::locale("C")): mLocale(loc) {}
			
		#else
			IsSpace(const std::locale& loc = std::locale("en_US.UTF-8")): mLocale(loc) {}

		#endif

		bool operator()(char c) const { return std::isspace(c, mLocale); }

	private:
		std::locale mLocale;
	};

	//predicate structure
	struct IsSlash: public std::unary_function<char, bool> {
		bool operator () (char c) const { return c == '/'; }
	};

	//predicate structure
	struct IsDelimeter: public std::unary_function<char, bool> {
		IsDelimeter(char delimeter): mDelimeter(delimeter) {}

		bool operator () (char c) const { return c == mDelimeter; }

	private:
		char mDelimeter;
	};

	//the tPredicate should have a bool operator()(char c) that returns true on a seperation character
	template <class tPredicate = IsSpace>
	class StringTokenizer {
	public:
		static void tokenize(
			const std::string& input, 
			std::vector<std::string>& output, 
			const tPredicate& predicate = tPredicate()
		);
	};

	template <class tPredicate>
	inline void StringTokenizer<tPredicate>::tokenize(const std::string& input, std::vector<std::string>& output, const tPredicate& predicate) {
		output.clear();

		std::string::const_iterator it = input.begin();
		std::string::const_iterator tokenEnd = input.begin();

		while (it != input.end()) {
			if (predicate(*it)) //if separator character was found
				++it; //just skip it
			else { 
				tokenEnd = std::find_if(it, input.end(), predicate); //find the end of the current token
				if (it < tokenEnd)
					output.push_back(std::string(it, tokenEnd));
				it = tokenEnd;
			}
		}
	};

	inline void trim(std::string& toTrim, const std::string& delimeters = " \t\r\n") {
		//too bad it's pretty complicated with the IsSpace thing :(
		toTrim.erase(0, toTrim.find_first_not_of(delimeters));
		toTrim.erase(toTrim.find_last_not_of(delimeters) + 1);
	}

	template <typename T>
	std::string toString(const T& t) {
		std::ostringstream s;
		s << t;
		return s.str();
	}

	template <typename T>
	T toType(const std::string& s) {
		T result;
		std::istringstream is;
		is.str(s);
		is >> result;
		return result;
	}

	template <>
	inline bool toType<bool>(const std::string& s) {
		if (s == "true")
			return true;
		return false;
	}
}

#endif
